package generic;

/**
 * @author ChangLiang
 * @date 2021/2/1
 */
public class GenericArray2<T> {

    /**
     *
     * 因为有了擦除，数组的运行时类型就只能是Object[]。
     * 如果我们像GenericArray中所使用的方式 立即将其转型为T[]，
     * 那么在编译期该数组的实际类型就将丢失，而编译器可能会错过某些潜在的错误检查。
     *
     * 正因为这样，最好是在集合内部使用Object[]，然后当你使用数组元素时，添加一个对T的转型。
     */
    private Object[] array;

    public GenericArray2(int sz) {
        array = new Object[sz];
    }

    public void put(int index, T item) {
        array[index] = item;
    }

    @SuppressWarnings("unchecked")
    public T get(int index) {
        return (T) array[index];
    }

    @SuppressWarnings("unchecked")
    public T[] rep() {
        /**
         * 但是，现在的内部表示是Object[]而不是T[]。
         * 当get()被调用时，它将对象转型为T，这实际上是正确的类型，因此这是安全的。
         *
         * 然而，如果你调用rep()，它还是尝试着将Object[]转型为T[]，这仍旧是不正确的，将在编译期产生警告，在运行时产生异常。
         * 因此，没有任何方式可以推翻底层的数组类型，它只能是Object[]。
         *
         * 在内部将array当作Object[]而不是T[]处理的优势是：我们不太可能忘记这个数组的运行时类型，从而意外地引人缺陷（尽
         * 管大多数也可能是所有这类缺陷都可以在运行时快速地探测到）。
         */
        return (T[]) array; // Warning: unchecked cast
    }

    public static void main(String[] args) {
        GenericArray2<Integer> gai =
                new GenericArray2<Integer>(10);
        for (int i = 0; i < 10; i++) {
            gai.put(i, i);
        }
        for (int i = 0; i < 10; i++) {
            System.out.print(gai.get(i) + " ");
        }
        System.out.println();
        try {
            Integer[] ia = gai.rep();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
